home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1996 July: Mac OS SDK / Dev.CD Jul 96 SDK / Dev.CD Jul 96 SDK2.toast / Development Kits (Disc 2) / QuickDraw GX / Programming Stuff / Sample Code / Typography Samples / Hebrew Layout ƒ / Hebrew Layout.c next >
Encoding:
C/C++ Source or Header  |  1995-04-10  |  17.5 KB  |  517 lines  |  [TEXT/KAHL]

  1. /**\
  2. |**| =====================================================================
  3. |**|
  4. |**|    Hebrew Layout.c
  5. |**|
  6. |**|    This file contains a sample of a layout shape using Hindi text.
  7. |**|    It requires the Ramatgan font if you don't want to see a lot of
  8. |**|    strange characters.
  9. |**|
  10. |**|    QuickDraw GX Libraries Used:
  11. |**|    "color library.c", "font library.c", "graphics debug library.c",
  12. |**|    "layout library.c", "shape library.c", "transferMode library.c",
  13. |**|    and "transform library.c"
  14. |**|
  15. |**|    ©1992-1994  Apple Computer, Inc.
  16. |**|    All rights reserved.
  17. |**|
  18. |**| =====================================================================
  19. \**/
  20.  
  21.  
  22. #include "QDGX shell.h"
  23. #include "layout routines.h"
  24. #include "layout library.h"
  25.  
  26.  
  27. /**\
  28. |**| ---------------------------------------------------------------------
  29. |**| PROTOTYPES
  30. |**| ---------------------------------------------------------------------
  31. \**/
  32.  
  33. // funtions required by shell
  34.  
  35. void    DoSetup            (void);
  36. void    DoDraw            (WindowPtr wind, Boolean updating);
  37. OSErr    DoCreateNew        (void);
  38. void    DoDispose        (WindowPtr wind);
  39. void    DoIdle            (WindowPtr wind);
  40. void    DoTeardown        (void);
  41. void    DoClick            (WindowPtr wind, Point p);
  42.  
  43. // private functions
  44.  
  45. OSErr    DoWindowInit        (WindowPtr wind);
  46. void    CreateSampleImage    (WindowPtr wind);
  47.  
  48.  
  49. /**\
  50. |**| ---------------------------------------------------------------------
  51. |**| ENUMS
  52. |**| ---------------------------------------------------------------------
  53. \**/
  54. enum { rWindResource = 128 };
  55.  
  56.  
  57. /**\
  58. |**| ---------------------------------------------------------------------
  59. |**| GLOBALS
  60. |**| ---------------------------------------------------------------------
  61. \**/
  62. // If gDebugging = TRUE, graphics library errors and notices will be posted.  This
  63. // functionality will only work with the "debugging" version of QuickDraw GX.
  64. // If the debugging version is not installed, nothing bad will happen, but these
  65. // functions will not work. 
  66.  
  67. Boolean        gDebugging = true;
  68.  
  69. // Set  "gGiveMeValidation" to TRUE if you want receive run-time validation.
  70.  
  71. Boolean        gGiveMeValidation = true;
  72.  
  73.  
  74. // gGraphicsHeapSize sets the size of the graphics heap created by calling the
  75. // GXNewGraphicsClient routine in main () within QuickDraw GX shell.c.  You can determine
  76. // the amount of graphics heap required by using GraphicsBug.  I'm giving it 600K,
  77. // since we need abunch if we have several windows open.
  78.  
  79. long        gGraphicsHeapSize = 600;
  80.  
  81. // gOurPrintingOverrideUPP is a universal proc pointer for our printing event
  82. // override.  This is so that our override can be native PowerPC code if necessary.
  83.  
  84. GXPrintingEventUPP    gOurPrintingOverrideUPP;
  85.  
  86.  
  87.  
  88. /**\
  89. |**| ---------------------------------------------------------------------
  90. |**| DoSetup()
  91. |**| Here's where we initialize any global variables our application needs.
  92. |**| We have only one at this time -- the universal proc pointer for
  93. |**| our printing override.
  94. |**| ---------------------------------------------------------------------
  95. \**/
  96. void DoSetup (void)
  97. {    // Initialize our printing event override UPP
  98.     gOurPrintingOverrideUPP = NewGXPrintingEventProc(MyPrintingEventOverride);
  99. }
  100.  
  101.  
  102. /**\
  103. |**| ---------------------------------------------------------------------
  104. |**| DoDraw()
  105. |**| Draw the contents of the window.  The first parameter is the window
  106. |**| to draw, and the second parameter is true if we're updating an existing
  107. |**| image.  If that's the case, we don't want to change anything, but
  108. |**| just draw what's already there.
  109. |**| ---------------------------------------------------------------------
  110. \**/
  111. void DoDraw (WindowPtr wind, Boolean updating)
  112. {
  113.      #pragma unused (updating)
  114.      GXDrawShape (GetDocShape(wind));
  115. }
  116.  
  117.  
  118. /**\
  119. |**| ---------------------------------------------------------------------
  120. |**| DoCreateNew()
  121. |**| This routine is called when a window needs to be created.
  122. |**| ---------------------------------------------------------------------
  123. \**/
  124. OSErr DoCreateNew (void)
  125. {
  126.     OSErr        err = noErr;
  127.     WindowPtr    wind;
  128.     
  129. // Get and create our window from the resource fork
  130.  
  131.     wind = GetNewWindow(rWindResource, nil, (WindowPtr)-1L);
  132.  
  133. // Attach a default gxViewPort to it, create and iInitialize our
  134. // private data for it, and add a sample image to its page shape.
  135.  
  136.     if ( wind == NULL )
  137.         return (MemError());
  138.  
  139.     GXIgnoreGraphicsNotice(transform_already_set);
  140.     SetDefaultViewPort(GXNewWindowViewPort(wind));            
  141.     GXPopGraphicsNotice();
  142.     
  143.     err = DoWindowInit(wind);
  144.     if ( err != noErr )
  145.         return err;
  146.     
  147.     CreateSampleImage(wind);
  148.     return err;
  149. }
  150.  
  151.  
  152. /**\
  153. |**| ---------------------------------------------------------------------
  154. |**| DoDispose()
  155. |**| This routine is called when a window needs to be disposed of.
  156. |**| ---------------------------------------------------------------------
  157. \**/
  158. void DoDispose (WindowPtr wind)
  159. {
  160.     TH_Doc    doc;
  161.     
  162. // You should always dispose of your GX graphics objects before tossing your window.
  163. // Why?  It's generally good form and this approach guarantees that everything is
  164. // disposed.  If you had not disposed of everything, the call to DisposeWindow should
  165. // dispose of the objects. If you are running the debugging version of QuickDraw GX
  166. // with notices set, you will receive a notice that you had not disposed of everything.
  167. // You can turn notices on in this file by setting gDebugging = TRUE (above).
  168.     
  169.     if ( wind != NULL )
  170.     {
  171.         doc = (TH_Doc)GetWRefCon(wind);        // Remember, this is where we stored our private data.
  172.         GXDisposeShape(GetDocShape(wind));     // Dispose of this doc's shape.
  173.         GXDisposeJob(GetDocJob(wind));        // Dispose of this doc's print job.
  174.         DisposHandle((Handle) doc);            // Dispose of our private data.
  175.         DisposeWindow(wind);                // Dispose of the window.
  176.     }
  177. }
  178.  
  179.  
  180. /**\
  181. |**| ---------------------------------------------------------------------
  182. |**| DoIdle()
  183. |**| This routine is called to do things while idling through the event loop.
  184. |**| ---------------------------------------------------------------------
  185. \**/
  186. void DoIdle (WindowPtr wind)
  187. {
  188. }
  189.  
  190.  
  191. /**\
  192. |**| ---------------------------------------------------------------------
  193. |**| DoTeardown()
  194. |**| This routine is called just before we quit to remove anything 
  195. |**| persistent that might have been setup by DoSetup().
  196. |**| ---------------------------------------------------------------------
  197. \**/
  198. void DoTeardown (void)
  199. {
  200.     DisposeRoutineDescriptor(gOurPrintingOverrideUPP);
  201. }
  202.  
  203.  
  204. /**\
  205. |**| ---------------------------------------------------------------------
  206. |**| DoClick()
  207. |**| ---------------------------------------------------------------------
  208. \**/
  209. void DoClick(WindowPtr window, Point p)
  210. {
  211. }
  212.  
  213.  
  214.  
  215.  
  216.  
  217. /**\
  218. |**| ---------------------------------------------------------------------
  219. |**| DoWindowInit()
  220. |**| In this function we create and initialize the the private document
  221. |**| structure for a new window.  This structure contains the print job and
  222. |**| the shape which is drawn in the window.  We store this data in a handle
  223. |**| and hang it off the window's refCon field for easy retrieval.  By doing
  224. |**| this, rather than using globals, we can create many windows containing
  225. |**| unique print jobs and shapes.
  226. |**| ---------------------------------------------------------------------
  227. \**/
  228. OSErr DoWindowInit (WindowPtr wind)
  229. {
  230.     OSErr    err = noErr;
  231.     gxJob    docJob;
  232.     gxShape    docPage;
  233.     TH_Doc    windDoc;
  234.  
  235.  
  236. // Create the page shape. We set the unique items attribute to make sure that each item
  237. // added to the picture has a unique reference. If this attribute was not set, we would
  238. // not see all copies of anything we add to the shape multiple times -- we'd just see
  239. // the last version added.        
  240.  
  241.     docPage = GXNewShape(gxPictureType);
  242.     GXSetShapeAttributes(docPage, (GXGetShapeAttributes(docPage) | gxUniqueItemsShape));
  243.     
  244.     
  245. // Create a print job for this document.  This will be the same as the system default until
  246. // the user goes through the dialogs for Page Setup or Print…
  247.  
  248.     err = GXNewJob(&docJob);
  249.     
  250.     
  251. // If there are no errors, create a handle the size of our document structure and store
  252. // the print job and page shape in it.  Store the handle in the window's refCon field so
  253. // that we can get at it.  (Note that the utility routines "GetDocJob" and "GetDocShape"
  254. // can be used to do this easily.
  255.  
  256.     if ( err == noErr )
  257.     {
  258.         windDoc = (TH_Doc) NewHandleClear(sizeof(T_Doc));
  259.  
  260.         if ( windDoc == NULL )
  261.             err = MemError();
  262.         else
  263.         {
  264.             (*windDoc)->docJob = docJob;
  265.             (*windDoc)->docPage = docPage;
  266.             SetWRefCon(wind, (long) windDoc);
  267.         }
  268.  
  269. // Now install our application override for PrintingEvent so that we can
  270. // support the new movable-modal printing dialog boxes.
  271.  
  272.         GXInstallApplicationOverride(docJob, gxPrintingEvent, gOurPrintingOverrideUPP);
  273.  
  274.     }
  275.  
  276.     return err;
  277. }
  278.  
  279.  
  280. /**\
  281. |**| ---------------------------------------------------------------------
  282. |**| CreateSampleImage()
  283. |**| This function creates primitive shapes and adds them to the window's page shape.
  284. |**| ---------------------------------------------------------------------
  285. \**/
  286. void CreateSampleImage (WindowPtr wind)
  287. {
  288.     Rect    ourWindowRect = wind->portRect; // the rectangle for this window
  289.                                             // in QuickDraw coordinates
  290.     gxShape layout;                        // the layout shape we build
  291.     gxShape highlight;                    // the highlight shape for the layout shape
  292.     gxShape thePage;                    // this window's document shape
  293.     gxRunControls runControls;            // run controls for the layout shape
  294.     gxLayoutOptions layoutOptions;        // options for the layout shape
  295.     gxStyle timesStyle;                    // a style record for a Times-based style
  296.     gxStyle helveticaStyle;                // ditto for Helvetica
  297.     gxStyle ramatganStyle;                 // ditto for Ramat Gan
  298.     gxStyle textStyles[5];                // an array of text style for our text runs
  299.     
  300. // These are the five text runs for this layout shape, in pieces because they're
  301. // in different languages
  302.     
  303.     char *text1 = "He said “";
  304.     
  305. // The following is "Macintosh" in Hebrew: 
  306. // meem, kouf, yod,  noon, teth, vav,  shin
  307. // (This assumes the standard Hebrew character set for Macintosh, by the way)
  308.     
  309.     static char text2[] = {0xEE, 0xF7, 0xE9, 0xF0, 0xE8, 0xE5, 0xF9, 0};
  310.     
  311.     char *text3 = " (Macintosh) ";
  312.  
  313. // The following is "Hebrew" in Hebrew: 
  314. // beth, ayin, beth, rech, yoh,  tav
  315. // Same character set assumptions.
  316.     
  317.     static char text4[] =    {0xE1, 0xF2, 0xE1, 0xF8, 0xE9, 0xFA, 0};
  318.  
  319.     char *text5 =         "” to me.";
  320.  
  321.     char *textRuns[5];                    // an array of pointers to text runs
  322.  
  323.     short textLengths[5];                // an array of the lengths of each run
  324.     short totalLength;                    // the total length of the layout's text
  325.     static short levelRunLengths[3];    // an array of the lengths of each level
  326.     static short levels[3] = {0, 1, 0};    // the level numbers for each level
  327.     
  328.     gxPoint posn;                        // the position of the layout shape
  329.  
  330.  
  331. // First, initialize the textRuns array to point to the five text runs
  332.     
  333.     textRuns[0] = text1;
  334.     textRuns[1] = text2;
  335.     textRuns[2] = text3;
  336.     textRuns[3] = text4;
  337.     textRuns[4] = text5;
  338.     
  339.     
  340. // Next, initialize the textLengths and levelRunLengths arrays.  MyStrLength() is
  341. // in this file.
  342.  
  343.     textLengths[0] = MyStrLength (text1);
  344.     textLengths[1] = MyStrLength (text2);
  345.     textLengths[2] = MyStrLength (text3);
  346.     textLengths[3] = MyStrLength (text4);
  347.     textLengths[4] = MyStrLength (text5);
  348.     
  349. // Our layout has three levels in it -- level 0 for the English runs at each end,
  350. // and level 1 for the Hebrew text in the middle.  We need the byte-count for each
  351. // level's text run in the levelRunLengths array.
  352.  
  353.     levelRunLengths[0] = textLengths[0];
  354.     levelRunLengths[1] = textLengths[1] + textLengths[2] + textLengths[3];
  355.     levelRunLengths[2] = textLengths[4];
  356.  
  357.     
  358. // totalLength is the length of all the text.
  359.  
  360.     totalLength = levelRunLengths[0] + levelRunLengths[1] + levelRunLengths[2];
  361.     
  362.  
  363. // make default gxLayoutOptions and gxRunControls structures
  364.  
  365.     InitializeLayoutOptions (&layoutOptions);
  366.     InitializeRunControls (&runControls);
  367.     
  368.     
  369. // Position the layout half way down the left edge of the window. Set 
  370. // the layout's width to the window's width and set the flushness to 1/2, this
  371. // will cause the layout to center in the window.  Note that ourWindowRect is
  372. // not in fixed coordinates, so we have to make it fixed to use it.
  373.  
  374.     layoutOptions.width = ff(ourWindowRect.right - ourWindowRect.left);
  375.     layoutOptions.flush = fract1/2;
  376.  
  377.     posn.x = 0;
  378.     posn.y = ff((ourWindowRect.bottom - ourWindowRect.top) / 2);
  379.     
  380.  
  381. // Create the styles we'll use.  The helveticaStyle is 30-point Helvetica.
  382. // NewLayoutStyle is a library routine found in layout library.c.  But first,
  383. // this important message:
  384.  
  385. // When I was converting this sample to actually print, I found this strange
  386. // problem that the highlight shape, while appearing correctly on the screen,
  387. // was always too far to the right when printed -- sometimes overlapping parts
  388. // of glyphs that shouldn't be highlighted.  An investigation was launched.
  389. //
  390. // It turns out that highlight shapes are pretty much always 72 DPI, because
  391. // they're polygons calculated from the metrics of the layout shape when the
  392. // highlight shape is created.  If you then scale the layout shape by
  393. // transforming it to 300 DPI or so (like a printer driver would do), the
  394. // highlight shape has the same geometry while hinting of the glyphs may have
  395. // changed the way the layout shape looks.  They've moved a little bit, perhaps,
  396. // and therefore the highlight shape isn't in the right place anymore.
  397. //
  398. // If this is for your on-screen work, you can recreate the highlight shape in
  399. // a zoomed viewPort, but you don't get to make the printer driver do that for
  400. // you.  So, instead, for each style run we use, we add the gxNoMetricsGridText
  401. // attribute.  This prevents QuickDraw GX from using hinting, so the glyphs always
  402. // scale the same way the highlight shape does, and all is well.
  403. //
  404. // (At first, I tried to fix this by adding gxNoMetricsGridShape to the layout
  405. // _shape's_ attributes, but that's not the right idea.  The attributes in the
  406. // shape's style affect any part of the layout that doesn't have a style of its
  407. // own, including any parts of the text for which the entry in the style array
  408. // is nil.  Since we're actually applying styles over the layout here, the
  409. // gxNoMetricsGridText must be set in those styles, not in the shape's style.)
  410. //
  411. // This does mean that your glyphs won't get hinting at low resolutions and
  412. // small point sizes where it might be desirable -- but it's really only a problem
  413. // if you're trying to print a highlight shape, which doesn't happen very often.
  414. // In fact, I can't really think of a legitimate reason to want to do it, except
  415. // maybe in sample code.
  416.     
  417.     helveticaStyle = NewLayoutStyle(
  418.         (char *) "\pHelvetica",                // the gxFontName for the style
  419.         ff(30),                                // the text size in fixed point
  420.         gxNoMetricsGridText,                // gxTextAttributes
  421.         &runControls,                        // run controls (our default ones)
  422.         nil,                                // run features (none for this style)
  423.         0,                                    // count of run features
  424.         nil);                                // style run overrides (none right now)
  425.  
  426. // The second style is ramatganStyle -- Ramat Gan (Hebrew), 36 points.
  427.  
  428.     ramatganStyle = NewLayoutStyle(
  429.         (char *) "\pRamatgan",                // gxFontName
  430.         ff(36),                                // text size (fixed point)
  431.         gxNoMetricsGridText,                // gxTextAttributes
  432.         &runControls,                        // run controls (our default ones)
  433.         nil,                                 // run features (none)
  434.         0,                                     // count of run features (none)
  435.         nil);                                // style run overrides (none)
  436.     
  437. // The final style is 30-point Times Roman.
  438.  
  439.     timesStyle = NewLayoutStyle(
  440.         (char *) "\pTimes Roman",             // gxFontName
  441.         ff(30),                             // text size (fixed point)
  442.         gxNoMetricsGridText,                // gxTextAttributes
  443.         &runControls,                         // run controls (our default ones)
  444.         nil,                                 // run features (none)
  445.         0,                                     // count of run features (none)
  446.         nil);                                // style run overrides (none)
  447.     
  448.  
  449. // Initialize the textStyles array so that each of the five runs has the right style
  450.  
  451.     textStyles[0] = helveticaStyle;
  452.     textStyles[1] = ramatganStyle;
  453.     textStyles[2] = timesStyle;
  454.     textStyles[3] = ramatganStyle;
  455.     textStyles[4] = helveticaStyle;
  456.     
  457.  
  458. // Setup complete!  Build the layout.
  459.  
  460.     layout = GXNewLayout(
  461.         5,                                // count of text runs
  462.         textLengths,                    // array of lengths of each run
  463.         (void *) textRuns,                // array of pointers to the text
  464.         5,                                // count of style runs
  465.         textLengths,                    // array of the byte lengths of each run
  466.         textStyles,                        // array of the styles
  467.         3,                                // number of levels in the layout
  468.         levelRunLengths,                // array of the lengths of each level
  469.         levels,                            // array of the levels
  470.         &layoutOptions,                    // options (default)
  471.         &posn);                            // position of the layout shape
  472.  
  473.     
  474. // Retrieve the page shape so we can add to it.
  475.  
  476.     thePage = GetDocShape(wind);
  477.     
  478. // Add the layout to the window's picture shape.  AddToShape is in shape library.c.
  479.  
  480.     AddToShape(thePage, layout);
  481.  
  482. // Make a highlight shape to highlight the layout from character 5 to character 20.
  483. // This will go from the level 0 English text into the level 2 English text
  484. // which is nested in the level 1 Hebrew text, and will produce a highlight shape
  485. // consisting of three disjoint rectangles because the Hebrew text is displayed
  486. // right-to-left.  SetShapeCommonTransfer is in transferMode library.c, and
  487. // SetShapeCommonColor is in color library.c.
  488.  
  489.     highlight = GXGetLayoutHighlight(
  490.         layout,                            // the layout shape to get the highlight from
  491.         5, 20,                             // starting and ending byte offsets
  492.         gxHighlightAverageAngle,         // highlight type -- use the average angle
  493.         nil);                            // a shape to use if we have one around (we don't)
  494.     
  495.     SetShapeCommonTransfer (highlight, gxHighlightMode);
  496.     SetShapeCommonColor (highlight, gxWhite);
  497.  
  498.     
  499.     AddToShape(thePage, highlight);
  500.     
  501.  
  502. // Dispose of what we allocated
  503.  
  504.     GXDisposeShape(highlight);
  505.     GXDisposeShape(layout);
  506.     GXDisposeStyle(helveticaStyle);
  507.     GXDisposeStyle(ramatganStyle);
  508.     GXDisposeStyle(timesStyle);
  509.     
  510.  
  511. // Invalidate the window's portRect so that everything gets updated.
  512.     
  513.     SetPort(wind);
  514.     InvalRect(&ourWindowRect);
  515. }
  516.  
  517.